package unit

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/robfig/cron/v3"
)

// OracleBackup 执行Oracle备份到临时目录
func OracleBackup(userName, passWord, sid, filename string) (string, error) {
	// 参数验证
	if userName == "" || passWord == "" || sid == "" || filename == "" {
		return "", fmt.Errorf("所有参数都不能为空")
	}

	// 创建临时目录
	tempDir, err := os.MkdirTemp("", "oracle_backup_")
	if err != nil {
		return "", fmt.Errorf("创建临时目录失败: %v", err)
	}

	// 构造完整备份文件路径
	backupFile := filepath.Join(tempDir, filename)

	// 执行exp命令
	cmd := exec.Command("exp", fmt.Sprintf("%s/%s@%s", userName, passWord, sid),
		"file="+backupFile)
	output, err := cmd.CombinedOutput()
	if err != nil {
		os.RemoveAll(tempDir) // 清理临时目录
		return "", fmt.Errorf("执行exp命令失败: %v, 输出: %s", err, string(output))
	}

	return backupFile, nil
}

// Compress7z 将文件压缩为7z格式到wwwroot目录
func Compress7z(source, target string) error {
	// 参数验证
	if source == "" || target == "" {
		return fmt.Errorf("源文件和目标文件不能为空")
	}

	// 检查源文件是否存在
	if _, err := os.Stat(source); os.IsNotExist(err) {
		return fmt.Errorf("源文件不存在: %s", source)
	}

	// 确保wwwroot目录存在
	wwwroot := filepath.Join(".", "wwwroot")
	if err := os.MkdirAll(wwwroot, 0755); err != nil {
		return fmt.Errorf("创建wwwroot目录失败: %v", err)
	}
	// 执行7z压缩命令
	cmd := exec.Command("7z", "a", target, source)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("压缩失败: %v, 输出: %s", err, string(output))
	}

	return nil
}

// OracleBackupAndCompress 执行Oracle备份并压缩为7z
func OracleBackupAndCompress(userName, passWord, sid, filename string) (string, error) {
	// 1. 执行Oracle备份
	backupFile, err := OracleBackup(userName, passWord, sid, filename)
	if err != nil {
		return "", err
	}
	defer os.Remove(filepath.Dir(backupFile)) // 确保临时目录被清理
	// 2. 构造7z文件名 按照日期生成文件名+filename+wwwroot下面
	now := time.Now()
	currentDateF := now.Format("2006-01-02_15-04-05") // 2023-06-27_14-20-30
	currentDate := fmt.Sprintf("%s_%s.7z", currentDateF, filename)
	zipFile := filepath.Join(".", "wwwroot", currentDate)
	fmt.Println("zipFile:", zipFile)
	// 3. 压缩备份文件
	if err := Compress7z(backupFile, zipFile); err != nil {
		return "", err
	}

	return zipFile, nil
}

// 清理旧备份文件
//
//	func CleanupOldBackups(backupDir string, retainDays int) error {
//		// Windows下使用forfiles命令清理旧文件
//		cmd := exec.Command("forfiles", "/p", backupDir, "/m", "*.7z", "/d", fmt.Sprintf("-%d", retainDays), "/c", "cmd /c del @file")
//		output, err := cmd.CombinedOutput()
//		if err != nil {
//			return fmt.Errorf("清理失败: %v, 输出: %s", err, string(output))
//		}
//		return nil
//	}
//
// 清理过期备份文件
func CleanupOldBackups(backupDir string, retainDays int) error {
	// 获取当前时间
	now := time.Now()

	// 计算过期时间点（当前时间往前推retainDays天）
	cutoffTime := now.AddDate(0, 0, -retainDays)
	// fmt.Println(retainDays)
	// 计算5分钟
	// retainDuration := 5 * time.Minute      // 5分钟
	// cutoffTime := now.Add(-retainDuration) // 减去时间间隔

	log.Printf("开始清理过期备份文件，保留最近%d天的文件", retainDays)
	log.Printf("将删除 %s 之前的文件", cutoffTime.Format("2006-01-02 15:04:05"))

	// 遍历备份目录
	err := filepath.Walk(backupDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 跳过目录本身
		if path == backupDir {
			return nil
		}

		// 只处理.7z备份文件
		if filepath.Ext(path) != ".7z" {
			return nil
		}

		// 检查文件修改时间
		if info.ModTime().Before(cutoffTime) {
			// 删除过期文件
			if err := os.Remove(path); err != nil {
				return fmt.Errorf("删除文件失败: %v", err)
			}
			log.Printf("已删除过期备份: %s (修改时间: %s)",
				filepath.Base(path),
				info.ModTime().Format("2006-01-02 15:04:05"))
		}

		return nil
	})

	if err != nil {
		return fmt.Errorf("遍历备份目录失败: %v", err)
	}

	return nil
}

// 执行完整备份流程
func performBackup(backupDir string, retainDays int, userName, passWord, sid, filename string) {
	log.Println("开始执行备份任务...")

	// 1. 清理旧备份
	if err := CleanupOldBackups(backupDir, retainDays); err != nil {
		log.Printf("清理旧备份失败: %v\n", err)
	}

	// 2. 执行Oracle备份
	zipFile, err := OracleBackupAndCompress(userName, passWord, sid, filename)
	if err != nil {
		log.Printf("备份压缩失败: %v\n", err)
		return
	}

	log.Printf("备份已成功创建并压缩为: %s\n", zipFile)
}

// 启动定时任务
func StartScheduler(backupDir string, retainDays int, userName, passWord, sid, filename string) {
	c := cron.New()

	// 每天中午12点执行
	_, err := c.AddFunc("0 12 * * *", func() {
		// // TODO: Replace these with your actual parameters or load from config/env
		// backupDir := backupDir
		// retainDays := retainDays
		// userName := userName
		// passWord := passWord
		// sid := sid
		// filename := filename
		performBackup(backupDir, retainDays, userName, passWord, sid, filename)
	})
	if err != nil {
		log.Fatalf("创建定时任务失败: %v", err)
	}

	c.Start()
	log.Println("定时备份任务已启动，每天中午12点执行")
}
